﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Security.Cryptography;
using System.IO.Compression;
using OpenComposite.Repository.Properties;
using System.Drawing;

namespace OpenComposite.EII.Repository
{
	[RepositoryItem(ItemType.Documentation, "documentation", "doc_id")]
	public class Documentation : RepositoryItemBaseEx
	{
		#region Initialization
		/// <summary>
		/// Initializes a new instance of the <see cref="Documentation"/> class.
		/// </summary>
		/// <param name="serviceProvider">The service provider.</param>
		/// <param name="bCreateNew">if set to <c>true</c> [b create new].</param>
		public Documentation(IServiceProvider serviceProvider, bool bCreateNew)
			: base("doc_id", "doc_nm", "doc_desc", "doc_ntext", "<New Documentation>")
		{
			if ( bCreateNew ) this.CreateNew();

			InitializeServiceProvider(serviceProvider);
		}
		#endregion

		#region RepositoryItemBaseEx Members
		/// <summary>
		/// Gets the image key.
		/// </summary>
		/// <value>The image key.</value>
		public override string ImageKey
		{
			get { return "documentation"; }
		}

		/// <summary>
		/// Gets the selected image key.
		/// </summary>
		/// <value>The selected image key.</value>
		public override string SelectedImageKey
		{
			get { return this.ImageKey; }
		}

		/// <summary>
		/// Gets the image.
		/// </summary>
		/// <value>The image.</value>
		public override System.Drawing.Image Image
		{
			get { return Resources.documentation_png; }
		}

		/// <summary>
		/// Gets the selected image.
		/// </summary>
		/// <value>The selected image.</value>
		public override System.Drawing.Image SelectedImage
		{
			get { return this.Image; }
		}

		/// <summary>
		/// Gets the type of the repository item.
		/// </summary>
		/// <value>The type of the repository item.</value>
		public override ItemType RepositoryItemType
		{
			get { return ItemType.Documentation; }
		}

		/// <summary>
		/// Gets the name of the repository item type.
		/// </summary>
		/// <value>The name of the repository item type.</value>
		public override string RepositoryItemTypeName
		{
			get { return "Documentation"; }
		}

		/// <summary>
		/// Gets the repository item type description.
		/// </summary>
		/// <value>The repository item type description.</value>
		public override string RepositoryItemTypeDescription
		{
			get { return ""; }
		}

		/// <summary>
		/// Gets the name of the table.
		/// </summary>
		/// <value>The name of the table.</value>
		public override string TableName
		{
			get { return "documentation"; }
		}

		/// <summary>
		/// Gets the allowed child types.
		/// </summary>
		/// <value>The allowed child types.</value>
		public override List<ItemType> AllowedChildTypes
		{
			get { return new List<ItemType>(); }
		}

		/// <summary>
		/// Gets the icon.
		/// </summary>
		/// <returns></returns>
		public override System.Drawing.Icon GetIcon()
		{
			return Icon.FromHandle(Resources.documentation_png.GetHicon());
		}

		/// <summary>
		/// Copies this instance.
		/// </summary>
		/// <param name="deep"><c>true</c> to recursively copy the item and all subitems;
		/// <c>false</c> to copy only the item itself.</param>
		/// <returns>The copied item.</returns>
		public override IRepositoryItem Copy(bool deep)
		{
			Documentation copy = new Documentation(this, true);
			this.CopyDataRowToTarget(copy);
			return copy;
		}
		#endregion

		#region Public Properties

		/// <summary>
		/// Gets or sets the document.
		/// </summary>
		/// <value>The document.</value>
		public string Document
		{
			get
			{
				return decryptDecompressString(this.NText);
			}
			set
			{
				this.NText = encryptCompressString(value);
			}
		}
		/// <summary>
		/// Gets or sets the binary document.
		/// </summary>
		/// <value>The binary document.</value>
		public byte[] BinaryDocument
		{
			get
			{
				return Convert.FromBase64String(decryptDecompressString(this.NText));
			}
			set
			{
				this.NText = encryptCompressString(Convert.ToBase64String(value));
			}
		}

		#endregion

		#region String En/Decryption

		// Encryption Key / IV
		private readonly byte[] KEY =
		new byte[] { 0x69, 0x26, 0x5a, 0x33, 0xf, 0xae, 0xbb, 0xb3, 0xda, 0xf8,
						 0xf3, 0xa7, 0xd9, 0xcc, 0xb4, 0xea, 0x11, 0x10, 0xe, 0x43,
						 0x66, 0x19, 0x2a, 0x99, 0x13, 0xe, 0xea, 0xa3, 0x7d, 0x69,
						 0xee, 0x24 };
		private readonly byte[] IV =
		new byte[] { 0x57, 0xd0, 0x8d, 0xf8, 0x1d, 0x1f, 0xb4, 0xcd, 0x24, 0xf0,
						 0xfd, 0xbb, 0x18, 0x28, 0x29, 0xe1 };

		private string encryptCompressString(string cleartext)
		{
			if ( string.IsNullOrEmpty(cleartext) ) return "";
			string encryptedtext = "";
			using ( MemoryStream ms = new MemoryStream() ) {
				try {
					RijndaelManaged myRijndael = new RijndaelManaged();
					//Get an encryptor.
					ICryptoTransform encryptor = myRijndael.CreateEncryptor(KEY, IV);
					//Encrypt the data.
					CryptoStream csEncrypt = new CryptoStream(ms, encryptor, CryptoStreamMode.Write);
					GZipStream zip = new GZipStream(csEncrypt, CompressionMode.Compress, true);
					StreamWriter sw = new StreamWriter(zip);
					sw.Write(cleartext);
					sw.Flush();
					zip.Flush();
					sw.Close();
					zip.Close();
					csEncrypt.FlushFinalBlock();
					csEncrypt.Close();
					byte[] buffer = ms.ToArray();
					encryptedtext = Convert.ToBase64String(buffer, 0, buffer.Length);
				} catch ( Exception ex ) {
					System.Diagnostics.Debug.WriteLine(ex.Message);
				}
			}
			return encryptedtext;
		}
		private string decryptDecompressString(string encryptedText)
		{
			if ( string.IsNullOrEmpty(encryptedText) ) return "";
			string cleartext = "";
			using ( MemoryStream ms = new MemoryStream(Convert.FromBase64String(encryptedText)) ) {
				RijndaelManaged myRijndael = new RijndaelManaged();
				//Get a decryptor.
				ICryptoTransform decryptor = myRijndael.CreateDecryptor(KEY, IV);
				//Decrypt the data.
				using ( CryptoStream csDecrypt = new CryptoStream(ms, decryptor, CryptoStreamMode.Read) )
				using ( GZipStream zip = new GZipStream(csDecrypt, CompressionMode.Decompress) )
				using ( StreamReader sr = new StreamReader(zip) ) {
					cleartext = sr.ReadToEnd();
				}
			}
			return cleartext;
		}

		#endregion

		/// <summary>
		/// Determines whether the Adobe Reader is installed.
		/// </summary>
		/// <returns>
		/// 	<c>true</c> if the Adobe Reader is installed; otherwise, <c>false</c>.
		/// </returns>
		public static bool IsReaderInstalled()
		{
			try {
				AcroPDFLib.AcroPDFClass pdf = new AcroPDFLib.AcroPDFClass();
				pdf.GetVersions();
			} catch { return false; }
			return true;
		}
	}
}
